package capricornus.actor.controller
{
	import capricornus.actor.Actor;
	import capricornus.actor.attribute.ActorAttribute;
	import capricornus.actor.events.ActorEvent;
	import capricornus.actor.utils.ActionType;
	import capricornus.utils.PointUtils;

	/**
	 * 移动控制器 
	 * @author kael
	 * 
	 */	
	public class ActorMoveController
	{
		protected var _actor:Actor;
		protected var _actorAttribute:ActorAttribute;
		
		protected var _addEventListener:Boolean = false;
		
		protected var _arrPath:Array;
		protected var _nextLength:Number;
		protected var _currentRunLength:Number = 0;
		protected var _currentNodeIndex:int = 0;
		protected var _currentNode:Array;
		protected var _nextNode:Array;
		
		//总共行走的路程
		protected var _pastLength:Number = 0;
		
		public function ActorMoveController( actor:Actor )
		{
			_actor = actor;
			init();
		}
		
		private function init():void
		{
			_actorAttribute = _actor.attribute;
			_actor.addEventListener( ActorEvent.ACTION_TYPE_CHANGED, onActionTypeChanged, false, 0, true );
		}
		
		public function destroy():void
		{
			_actor.removeEventListener( ActorEvent.ACTION_TYPE_CHANGED, onActionTypeChanged );
			stop();
		}
		
		public function get pastLength():Number
		{
			return _pastLength;
		}
		
		public function get isMoving():Boolean
		{
			return _addEventListener;
		}
		
		public function stop():void
		{
			addMovePath( null );
		}
		
		public function addMovePath( arrPath:Array ):void
		{
			_arrPath = arrPath;
			if( _arrPath==null || _arrPath.length==0 ) 
			{
				removeEventAndSendStop();
				return;
			}
			
			_currentNode = _arrPath[0];
			_currentNodeIndex = 0;
			_currentRunLength = 0;
			_nextNode = nextNode();
			
			if( _nextNode==null ) 
			{
				removeEventAndSendStop();
				return;
			}
			
			_actor.setLocation( _currentNode[0], _currentNode[1] );
			_nextLength = PointUtils.getLength( _currentNode, _nextNode );
			if( !_addEventListener )
			{
				_addEventListener = true;
				_actor.addEventListener( ActorEvent.ACTOR_REFRESH, onRefresh, false, 0, true );
			}
			_actor.dispatchEvent( new ActorEvent( ActorEvent.MOVE_START, [_currentNode, _nextNode] ) );
		}
		
		public function refresh( time:uint ):void
		{
			if( _nextNode != null ) move( time );
		}
		
		protected function onActionTypeChanged( e:ActorEvent ):void
		{
			if( e.data != ActionType.MOVED )
			{
				if( !_actor.stunning )
				{
					addMovePath( null );
				}
			}
		}
		
		/**
		 * 统一在Actor里面刷新，这个函数暂时用不到 
		 * @param e
		 * 
		 */		
		protected function onRefresh( e:ActorEvent ):void
		{
//			move( uint(e.data) );
		}
		
		protected function nextNode():Array
		{
			_currentNodeIndex++;
			if( _currentNodeIndex < _arrPath.length )
			{
				return _arrPath[_currentNodeIndex];
			}
			return null;
		}
		
		protected function move( time:uint ):void
		{
			var t:Number = _actorAttribute.speed * time;
			_currentRunLength += t;
			_pastLength += t; 
			
			var b:Boolean = false;
			while( _currentRunLength >= _nextLength )
			{
				_currentRunLength -= _nextLength;
				
				b = true;
				_currentNode = _nextNode;
				_nextNode = nextNode();
				if( _nextNode==null ) break;
				_nextLength = PointUtils.getLength( _currentNode, _nextNode );
			}
			
			if( _nextNode != null )
			{
				var arr:Array = PointUtils.interpolate2( _currentNode, _nextNode, _currentRunLength, _nextLength );
				_actor.setLocation( arr[0], arr[1] );
				if( b ) 
				{
					_actor.dispatchEvent( new ActorEvent( ActorEvent.MOVE_DIRECT_CHANGED, [_currentNode, _nextNode] ) );
				}
			}
			else
			{
				_actor.setLocation( _currentNode[0], _currentNode[1] );
			}
			
			if( _currentNodeIndex >= _arrPath.length )
			{
				removeEventAndSendStop();
			}
		}
		
		public function removeEventAndSendStop():void
		{
			if( _addEventListener )
			{
				_addEventListener = false;
				_actor.removeEventListener( ActorEvent.ACTOR_REFRESH, onRefresh );
				_actor.dispatchEvent( new ActorEvent( ActorEvent.MOVE_STOP ) );
			}
		}
	}
}









